home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 / SpriteWorld files / Sources / BlitPixieDoubleRect.c < prev    next >
Encoding:
Text File  |  1999-01-14  |  31.4 KB  |  1,313 lines  |  [TEXT/CWIE]

  1. //--------------------------------------------------------------
  2. //    BlitPixieDoubleRect, v 4.4
  3. //    by Anders Björklund, May 1998
  4. //
  5. //    This file contains the DrawProcs for use with the 
  6. //    SWSetSpriteWorldDoubleRectDrawProc function in Scrolling.c.
  7. //--------------------------------------------------------------
  8.  
  9. #include <SWIncludes.h>
  10.  
  11. //#define THEORY            // uncomment this to use the "theoretical" version
  12. //#define USE_C                // uncomment this to use the C version of the blitter
  13.  
  14. typedef struct OffsetInfo
  15. {
  16.     long     srcOffsetAtoB;    // offset from right of rect A to left of rect B
  17.     long     srcOffsetBtoA;    // offset from right of rect B to left of rect A, in next row
  18.     long     dstOffsetAtoB;
  19.     long     dstOffsetBtoA;
  20. } OffsetInfo, *OffsetInfoPtr;
  21.  
  22. static void BlitDoubleRects(
  23.     char *src,
  24.     char *dst,
  25.     unsigned long rows,
  26.     unsigned long bytesA,
  27.     unsigned long bytesB,
  28.     OffsetInfoPtr info
  29.     );
  30.  
  31. //--------------------------------------------------------------------------------------
  32. #pragma mark [Macros]
  33.  
  34.     // Note: this version of CLIP_RECT is different from the BP_CLIP_RECT in BlitPixie.h!
  35.     // This version is designed to handle DoubleRect DrawProcs.
  36.  
  37. //#define CLIP_RECT(clip, src, dst, interlaced)
  38. #define CLIP_RECT(r, r1, r2, interlaced) \
  39.     /* clip off the top so we don't write into random memory */ \
  40.     if (r2.top < r.top) { \
  41.         r1.top += r.top - r2.top; \
  42.         r2.top =  r.top; \
  43.     } \
  44.     /* clip off the bottom */ \
  45.     if (r2.bottom > r.bottom) {     \
  46.         r1.bottom -= r2.bottom - r.bottom; \
  47.         r2.bottom = r.bottom;     \
  48.     }                             \
  49.     /* clip off the left */ \
  50.     if (r2.left < r.left) { \
  51.         r1.left += r.left - r2.left; \
  52.         r2.left = r.left; \
  53.     } \
  54.     /* clip off the right */ \
  55.     if (r2.right > r.right) { \
  56.         r1.right -= r2.right - r.right; \
  57.         r2.right = r.right; \
  58.     } \
  59.     if (interlaced) { \
  60.         /* If first line is not on an even number, then skip it. */ \
  61.         if ((r2.top - r.top) & 1) { \
  62.             r1.top++; \
  63.             r2.top++; \
  64.         } \
  65.     } \
  66.     /* Make sure height is valid */ \
  67.     if (r2.bottom <= r2.top) \
  68.         return; \
  69.     /* Make sure width is valid  */ \
  70.     /* Instead of returning, we set the width to 0, so the other rect can be drawn */ \
  71.     if (r2.right < r2.left) { \
  72.         r1.right = r1.left; \
  73.         r2.right = r2.left; \
  74.     }
  75.  
  76.  
  77. extern SInt8    gSWmmuMode;
  78.  
  79.  
  80. ///--------------------------------------------------------------------------------------
  81. //        BlitPixie8BitDoubleRectDrawProc
  82. ///--------------------------------------------------------------------------------------
  83.  
  84. SW_FUNC void BlitPixie8BitDoubleRectDrawProc(
  85.     FramePtr srcFrameP,
  86.     FramePtr dstFrameP,
  87.     Rect* srcRectA,
  88.     Rect* dstRectA,
  89.     Rect* srcRectB,
  90.     Rect* dstRectB)
  91. {
  92.     OffsetInfo        info;
  93.     Rect            srcBlitRectA = *srcRectA,
  94.                     dstBlitRectA = *dstRectA,
  95.                     srcBlitRectB = *srcRectB,
  96.                     dstBlitRectB = *dstRectB;
  97.     
  98.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  99.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
  100.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
  101.     
  102.     CLIP_RECT(dstFrameP->frameRect, srcBlitRectA, dstBlitRectA, false)
  103.     CLIP_RECT(dstFrameP->frameRect, srcBlitRectB, dstBlitRectB, false)
  104.  
  105.     info.srcOffsetAtoB = srcBlitRectB.left - srcBlitRectA.right;
  106.     info.srcOffsetBtoA = (srcBlitRectA.left - srcBlitRectB.right) +
  107.         srcFrameP->frameRowBytes;
  108.     info.dstOffsetAtoB = dstBlitRectB.left - dstBlitRectA.right;
  109.     info.dstOffsetBtoA = (dstBlitRectA.left - dstBlitRectB.right) +
  110.         dstFrameP->frameRowBytes;
  111.     
  112.     START_32_BIT_MODE
  113.  
  114.         BlitDoubleRects(
  115.                 // calculate the address of the first byte of the source
  116.             (srcFrameP->frameBaseAddr + 
  117.                 (srcFrameP->scanLinePtrArray[srcBlitRectA.top - srcFrameP->frameRect.top]) + 
  118.                 srcBlitRectA.left),
  119.  
  120.                 // calculate the address of the first byte of the destination
  121.             (dstFrameP->frameBaseAddr + 
  122.                 (dstFrameP->scanLinePtrArray[dstBlitRectA.top]) +
  123.                 dstBlitRectA.left),
  124.  
  125.                 // calculate the number of rows to blit
  126.             dstBlitRectA.bottom - dstBlitRectA.top,
  127.         //  == dstBlitRectB.bottom - dstBlitRectB.top
  128.             
  129.                 // pass rect widths and offset info
  130.             dstBlitRectA.right - dstBlitRectA.left,
  131.             dstBlitRectB.right - dstBlitRectB.left,
  132.             &info
  133.         );
  134.  
  135.     END_32_BIT_MODE
  136.     
  137. }
  138.  
  139. ///--------------------------------------------------------------------------------------
  140. //        BP8BitInterlacedDoubleRectDrawProc
  141. ///--------------------------------------------------------------------------------------
  142.  
  143. SW_FUNC void BP8BitInterlacedDoubleRectDrawProc(
  144.     FramePtr srcFrameP,
  145.     FramePtr dstFrameP,
  146.     Rect* srcRectA,
  147.     Rect* dstRectA,
  148.     Rect* srcRectB,
  149.     Rect* dstRectB)
  150. {
  151.     OffsetInfo        info;
  152.     Rect            srcBlitRectA = *srcRectA,
  153.                     dstBlitRectA = *dstRectA,
  154.                     srcBlitRectB = *srcRectB,
  155.                     dstBlitRectB = *dstRectB;
  156.     int                numRowsToCopy;
  157.     
  158.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  159.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
  160.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
  161.     
  162.     CLIP_RECT(dstFrameP->frameRect, srcBlitRectA, dstBlitRectA, true)
  163.     CLIP_RECT(dstFrameP->frameRect, srcBlitRectB, dstBlitRectB, true)
  164.  
  165.     numRowsToCopy = dstBlitRectA.bottom - dstBlitRectA.top;
  166.         // Is destBlitRect height an even number?
  167.     if ( ! (numRowsToCopy & 1) )
  168.         numRowsToCopy >>= 1;
  169.     else
  170.         numRowsToCopy = (numRowsToCopy>>1) + 1;
  171.     if (numRowsToCopy < 1)
  172.         return;
  173.  
  174.     info.srcOffsetAtoB = srcBlitRectB.left - srcBlitRectA.right;
  175.     info.srcOffsetBtoA = (srcBlitRectA.left - srcBlitRectB.right) + 
  176.             (srcFrameP->frameRowBytes << 1);
  177.     info.dstOffsetAtoB = dstBlitRectB.left - dstBlitRectA.right;
  178.     info.dstOffsetBtoA = (dstBlitRectA.left - dstBlitRectB.right) +
  179.         (dstFrameP->frameRowBytes << 1);
  180.     
  181.     START_32_BIT_MODE
  182.  
  183.         BlitDoubleRects(
  184.                 // calculate the address of the first byte of the source
  185.             (srcFrameP->frameBaseAddr + 
  186.                 (srcFrameP->scanLinePtrArray[srcBlitRectA.top - srcFrameP->frameRect.top]) + 
  187.                 srcBlitRectA.left),
  188.  
  189.                 // calculate the address of the first byte of the destination
  190.             (dstFrameP->frameBaseAddr + 
  191.                 (dstFrameP->scanLinePtrArray[dstBlitRectA.top]) +
  192.                 dstBlitRectA.left),
  193.  
  194.                 // calculate the number of rows to blit
  195.             numRowsToCopy,
  196.             
  197.                 // pass rect widths and offset info
  198.             SW_MAX(dstBlitRectA.right - dstBlitRectA.left,0),
  199.             SW_MAX(dstBlitRectB.right - dstBlitRectB.left,0),
  200.             &info
  201.         );
  202.  
  203.     END_32_BIT_MODE
  204. }
  205.  
  206. ///--------------------------------------------------------------------------------------
  207. //        BlitPixie16BitDoubleRectDrawProc
  208. ///--------------------------------------------------------------------------------------
  209.  
  210. SW_FUNC void BlitPixie16BitDoubleRectDrawProc(
  211.     FramePtr srcFrameP,
  212.     FramePtr dstFrameP,
  213.     Rect* srcRectA,
  214.     Rect* dstRectA,
  215.     Rect* srcRectB,
  216.     Rect* dstRectB)
  217. {
  218.     OffsetInfo        info;
  219.     Rect            srcBlitRectA = *srcRectA,
  220.                     dstBlitRectA = *dstRectA,
  221.                     srcBlitRectB = *srcRectB,
  222.                     dstBlitRectB = *dstRectB;
  223.     
  224.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  225.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
  226.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
  227.     
  228.     CLIP_RECT(dstFrameP->frameRect, srcBlitRectA, dstBlitRectA, false)
  229.     CLIP_RECT(dstFrameP->frameRect, srcBlitRectB, dstBlitRectB, false)
  230.  
  231.     info.srcOffsetAtoB = (srcBlitRectB.left - srcBlitRectA.right) << 1;
  232.     info.srcOffsetBtoA = ((srcBlitRectA.left - srcBlitRectB.right) << 1 ) +
  233.             srcFrameP->frameRowBytes;
  234.     info.dstOffsetAtoB = (dstBlitRectB.left - dstBlitRectA.right) << 1;
  235.     info.dstOffsetBtoA = ((dstBlitRectA.left - dstBlitRectB.right) << 1) +
  236.         dstFrameP->frameRowBytes;
  237.     
  238.     START_32_BIT_MODE
  239.  
  240.         BlitDoubleRects(
  241.                 // calculate the address of the first byte of the source
  242.             (srcFrameP->frameBaseAddr + 
  243.                 (srcFrameP->scanLinePtrArray[srcBlitRectA.top - srcFrameP->frameRect.top]) + 
  244.                 (srcBlitRectA.left << 1)),
  245.  
  246.                 // calculate the address of the first byte of the destination
  247.             (dstFrameP->frameBaseAddr + 
  248.                 (dstFrameP->scanLinePtrArray[dstBlitRectA.top]) +
  249.                 (dstBlitRectA.left << 1)),
  250.  
  251.                 // calculate the number of rows to blit
  252.             dstBlitRectA.bottom - dstBlitRectA.top,
  253.         //  == dstBlitRectB.bottom - dstBlitRectB.top
  254.             
  255.                 // pass rect widths and offset info
  256.             SW_MAX(dstBlitRectA.right - dstBlitRectA.left,0) << 1,
  257.             SW_MAX(dstBlitRectB.right - dstBlitRectB.left,0) << 1,
  258.             &info
  259.         );
  260.  
  261.     END_32_BIT_MODE
  262. }
  263.  
  264.  
  265. ///--------------------------------------------------------------------------------------
  266. //        BP16BitInterlacedDoubleRectDrawProc
  267. ///--------------------------------------------------------------------------------------
  268.  
  269. SW_FUNC void BP16BitInterlacedDoubleRectDrawProc(
  270.     FramePtr srcFrameP,
  271.     FramePtr dstFrameP,
  272.     Rect* srcRectA,
  273.     Rect* dstRectA,
  274.     Rect* srcRectB,
  275.     Rect* dstRectB)
  276. {
  277.     OffsetInfo        info;
  278.     Rect            srcBlitRectA = *srcRectA,
  279.                     dstBlitRectA = *dstRectA,
  280.                     srcBlitRectB = *srcRectB,
  281.                     dstBlitRectB = *dstRectB;
  282.     int                numRowsToCopy;
  283.     
  284.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  285.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
  286.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
  287.     
  288.     CLIP_RECT(dstFrameP->frameRect, srcBlitRectA, dstBlitRectA, true)
  289.     CLIP_RECT(dstFrameP->frameRect, srcBlitRectB, dstBlitRectB, true)
  290.  
  291.     numRowsToCopy = dstBlitRectA.bottom - dstBlitRectA.top;
  292.         // Is destBlitRect height an even number?
  293.     if ( ! (numRowsToCopy & 1) )
  294.         numRowsToCopy >>= 1;
  295.     else
  296.         numRowsToCopy = (numRowsToCopy>>1) + 1;
  297.     if (numRowsToCopy < 1)
  298.         return;
  299.  
  300.     info.srcOffsetAtoB = (srcBlitRectB.left - srcBlitRectA.right) << 1;
  301.     info.srcOffsetBtoA = ((srcBlitRectA.left - srcBlitRectB.right) << 1 ) +
  302.             (srcFrameP->frameRowBytes << 1);
  303.     info.dstOffsetAtoB = (dstBlitRectB.left - dstBlitRectA.right) << 1;
  304.     info.dstOffsetBtoA = ((dstBlitRectA.left - dstBlitRectB.right) << 1 ) +
  305.             (dstFrameP->frameRowBytes << 1);
  306.     
  307.     START_32_BIT_MODE
  308.  
  309.         BlitDoubleRects(
  310.                 // calculate the address of the first byte of the source
  311.             (srcFrameP->frameBaseAddr + 
  312.                 (srcFrameP->scanLinePtrArray[srcBlitRectA.top - srcFrameP->frameRect.top]) + 
  313.                 (srcBlitRectA.left << 1)),
  314.  
  315.                 // calculate the address of the first byte of the destination
  316.             (dstFrameP->frameBaseAddr + 
  317.                 (dstFrameP->scanLinePtrArray[dstBlitRectA.top]) +
  318.                 (dstBlitRectA.left << 1)),
  319.  
  320.                 // calculate the number of rows to blit
  321.             numRowsToCopy,
  322.             
  323.                 // pass rect widths and offset info
  324.             SW_MAX(dstBlitRectA.right - dstBlitRectA.left,0) << 1,
  325.             SW_MAX(dstBlitRectB.right - dstBlitRectB.left,0) << 1,
  326.             &info
  327.         );
  328.  
  329.     END_32_BIT_MODE
  330. }
  331.  
  332.         
  333. #pragma mark -
  334.  
  335. ///--------------------------------------------------------------------------------------
  336. //        BlitDoubleRects
  337. //
  338. //        a blitter to merge two offscreen areas into one onscreen area
  339. //        NOTE: This implementation _always_ blits aligned doubles to the screen
  340. ///--------------------------------------------------------------------------------------
  341.  
  342. #pragma mark *** Theory:
  343. #ifdef THEORY
  344.  
  345. #include <Memory.h>                    
  346.  
  347. #if SW_PPC
  348. #define BlockMoveFunction        BlockMoveDataUncached
  349. // BlockMoveDataUncached is implemented in "DriverServicesLib" (strangely enough).
  350. // Even more strangely, DriverServicesLib is only available on PCI-based Macs -
  351. // making it kinda hard to run on others. Just include this library in your project,
  352. // or go with BlockMoveData/memcpy (and suffer the consequences). -- AFB
  353. //
  354. // "the difference between theory and practice is greater in practice than in theory"
  355. #else
  356. #define BlockMoveFunction        BlockMoveData
  357. #endif
  358.  
  359. void BlitDoubleRects(
  360.     char *src,
  361.     char *dst,
  362.     unsigned long rows,
  363.     unsigned long bytesA,
  364.     unsigned long bytesB,
  365.     OffsetInfoPtr info)
  366. {
  367.     int        y;
  368.  
  369.     for ( y = 0; y < rows; y++ )
  370.     {
  371.         BlockMoveFunction( src, dst , bytesA );
  372.         src += bytesA;
  373.         dst += bytesA;
  374.         
  375.         src += info->srcOffsetAtoB;
  376.         dst += info->dstOffsetAtoB;
  377.  
  378.         BlockMoveFunction( src, dst , bytesB );
  379.         src += bytesB;
  380.         dst += bytesB;
  381.         
  382.         src += info->srcOffsetBtoA;
  383.         dst += info->dstOffsetBtoA;
  384.     }
  385. }
  386.  
  387. #pragma mark *** C (optimized):
  388. #elif defined(USE_C)
  389.  
  390. #if THINK_C
  391. // NOTE:    This code will not compile on THINK C, because it doesn't have decent pointers.
  392. //            Use a real compiler instead, or switch back to the assembly. Thank you.
  393. #error
  394. #endif
  395.  
  396. //    This implementation is
  397. //    ©1998 Anders Fredrik Björklund. All rights reserved.
  398.  
  399. #define    srcL        ((long *) src)
  400. #define    dstL        ((long *) dst)
  401. #define bufferL        ((long *) buffer)
  402. #define    srcD        ((double *) src)
  403. #define    dstD        ((double *) dst)
  404. #define bufferD        ((double *) buffer)
  405.  
  406. #if SW_PPC
  407. #define kAlignmentMask        7
  408. #else
  409. #define kAlignmentMask        3
  410. #endif
  411.  
  412. void BlitDoubleRects(
  413.     char *src,
  414.     char *dst,
  415.     unsigned long rows,
  416.     unsigned long bytesA,
  417.     unsigned long bytesB,
  418.     OffsetInfoPtr info)
  419. {
  420.     char                *buffer;
  421.     unsigned int        x;
  422.  
  423.     unsigned int        leftblocks,leftwords,left;
  424.     unsigned int        rightblocks,rightwords,right;
  425.     unsigned int        alignA,alignB;
  426.     long                srcOffsetBtoA,dstOffsetBtoA,srcOffsetAtoB,dstOffsetAtoB;
  427. #if SW_PPC
  428.     Boolean                useDoublesA,useDoublesB;
  429.     char                DoubleBuffer[64];
  430. #endif
  431.         
  432.         // load stuff from struct
  433.     srcOffsetAtoB = info->srcOffsetAtoB;
  434.     dstOffsetAtoB = info->dstOffsetAtoB;
  435.     srcOffsetBtoA = info->srcOffsetBtoA;
  436.     dstOffsetBtoA = info->dstOffsetBtoA;
  437.     
  438.         // alignment offset for rect A
  439.     alignA = (-((long) dst )) & kAlignmentMask;
  440.     if ( alignA > bytesA)    alignA = bytesA;
  441.     bytesA -= alignA;
  442.  
  443.         // alignment offset for rect B
  444.     alignB = (-((long) dst + bytesA + dstOffsetAtoB)) & kAlignmentMask;
  445.     if ( alignB > bytesB)    alignB = bytesB;
  446.     bytesB -= alignB;
  447.  
  448.         //pre-calculate transfer sizes
  449.     leftblocks = bytesA >> 5;
  450.     left = bytesA & 31;
  451.     rightblocks = bytesB >> 5;
  452.     right = bytesB & 31;
  453.  
  454. #if SW_PPC
  455.  
  456.         // alignment for source     (can use doubles if word-aligned)
  457.     useDoublesA =    (alignA & 3) == ((-((long) src )) & 3);
  458.     useDoublesB =    (alignB & 3) == ((-((long) src + bytesA + srcOffsetAtoB)) & 3);
  459.  
  460.         // align buffer to 32-byte boundary (cache line)
  461.     buffer = (char *) (( (long) DoubleBuffer + 32) & ~31L);    
  462.  
  463.     #define COPY_BLOCKS_LONG(blocks)    \
  464.         for ( x = 0; x < blocks; x++)                                            \
  465.         {    register long        t1,t2,t3,t4;                                    \
  466.             register double        f1,f2,f3,f4;                                    \
  467.             t1 = srcL[0]; t2 = srcL[1]; t3 = srcL[2]; t4 = srcL[3];                \
  468.             bufferL[0] = t1; bufferL[1] = t2; bufferL[2] = t3; bufferL[3] = t4;    \
  469.             t1 = srcL[4]; t2 = srcL[5]; t3 = srcL[6]; t4 = srcL[7];    srcL += 8;    \
  470.             f1 = bufferD[0]; f2 = bufferD[1];                                    \
  471.             bufferL[4] = t1; bufferL[5] = t2; bufferL[6] = t3; bufferL[7] = t4;    \
  472.             f3 = bufferD[2]; f4 = bufferD[3];                                    \
  473.             dstD[0] = f1; dstD[1] = f2; dstD[2] = f3; dstD[3] = f4; dstD += 4;    \
  474.         }    
  475.     
  476.     #define COPY_LEFTOVER_LONG(longs,bytes)                                        \
  477.         for ( x = 0; x < longs; x++)    *dstL++ = *srcL++;                        \
  478.         if ( bytes & 2)                    *((short *)dst)++ = *((short *)src)++;    \
  479.         if ( bytes & 1)                    *((char *)dst)++ = *((char *)src)++;
  480.  
  481.     #define COPY_BLOCKS_DOUBLE(blocks)                                            \
  482.         for ( x = 0; x < blocks; x++)                                            \
  483.         {    register double    t1,t2,t3,t4;                                        \
  484.             t1 = srcD[0]; t2 = srcD[1]; t3 = srcD[2]; t4 = srcD[3]; srcD += 4;    \
  485.             dstD[0] = t1; dstD[1] = t2; dstD[2] = t3; dstD[3] = t4; dstD += 4;    \
  486.         }
  487.     #define COPY_LEFTOVER_DOUBLE(doubles,bytes)                                    \
  488.         for ( x = 0; x < doubles; x++)    *dstD++ = *srcD++;                        \
  489.         if ( bytes & 4)                    *((long *)dst)++ = *((long *)src)++;    \
  490.         if ( bytes & 2)                    *((short *)dst)++ = *((short *)src)++;    \
  491.         if ( bytes & 1)                    *((char *)dst)++ = *((char *)src)++;
  492.  
  493.     #define COPY_ALIGN(align)                                                    \
  494.         if ( align & 4)                    *((long *)dst)++ = *((long *)src)++;    \
  495.         if ( align & 1)                    *((char *)dst)++ = *((char *)src)++;    \
  496.         if ( align & 2)                    *((short *)dst)++ = *((short *)src)++;
  497.  
  498. // ----------------------------------------------------------------------------
  499.         
  500.     if ( useDoublesA && useDoublesB )    // Both rects aligned
  501.     {
  502.         leftwords = left >> 3;
  503.         rightwords = right >> 3;
  504.         
  505.         do
  506.         {                
  507.             COPY_ALIGN(alignA)
  508.             COPY_BLOCKS_DOUBLE(leftblocks)
  509.             COPY_LEFTOVER_DOUBLE(leftwords,left)
  510.             src += srcOffsetAtoB;
  511.             dst += dstOffsetAtoB;
  512.  
  513.             COPY_ALIGN(alignB)
  514.             COPY_BLOCKS_DOUBLE(rightblocks)
  515.             COPY_LEFTOVER_DOUBLE(rightwords,right)
  516.             src += srcOffsetBtoA;
  517.             dst += dstOffsetBtoA;
  518.         }
  519.         while (--rows);
  520.     }    
  521.     else if ( useDoublesA )    // Left rect aligned
  522.     {
  523.         leftwords = left >> 3;
  524.         rightwords = right >> 2;
  525.         
  526.         do
  527.         {                
  528.             COPY_ALIGN(alignA)
  529.             COPY_BLOCKS_DOUBLE(leftblocks)
  530.             COPY_LEFTOVER_DOUBLE(leftwords,left)
  531.             src += srcOffsetAtoB;
  532.             dst += dstOffsetAtoB;
  533.  
  534.             COPY_ALIGN(alignB)
  535.             COPY_BLOCKS_LONG(rightblocks)
  536.             COPY_LEFTOVER_LONG(rightwords,right)
  537.             src += srcOffsetBtoA;
  538.             dst += dstOffsetBtoA;
  539.         }
  540.         while (--rows);
  541.     }
  542.     else if ( useDoublesB )    // Right rect aligned
  543.     {
  544.         leftwords = left >> 2;
  545.         rightwords = right >> 3;
  546.         
  547.         do
  548.         {                
  549.             COPY_ALIGN(alignA)
  550.             COPY_BLOCKS_LONG(leftblocks)
  551.             COPY_LEFTOVER_LONG(leftwords,left)
  552.             src += srcOffsetAtoB;
  553.             dst += dstOffsetAtoB;
  554.  
  555.             COPY_ALIGN(alignB)
  556.             COPY_BLOCKS_DOUBLE(rightblocks)
  557.             COPY_LEFTOVER_DOUBLE(rightwords,right)
  558.             src += srcOffsetBtoA;
  559.             dst += dstOffsetBtoA;
  560.         }
  561.         while (--rows);
  562.     }
  563.     else    // None of the rects aligned
  564.     {    
  565.         leftwords = left >> 2;
  566.         rightwords = right >> 2;
  567.         
  568.         do
  569.         {                
  570.             COPY_ALIGN(alignA)
  571.             COPY_BLOCKS_LONG(leftblocks)
  572.             COPY_LEFTOVER_LONG(leftwords,left)
  573.             src += srcOffsetAtoB;
  574.             dst += dstOffsetAtoB;
  575.  
  576.             COPY_ALIGN(alignB)
  577.             COPY_BLOCKS_LONG(rightblocks)
  578.             COPY_LEFTOVER_LONG(rightwords,right)
  579.             src += srcOffsetBtoA;
  580.             dst += dstOffsetBtoA;
  581.         }
  582.         while (--rows);
  583.     }
  584.  
  585. #else // ! SW_PPC
  586.  
  587.     leftwords = left >> 2;
  588.     rightwords = right >> 2;
  589.     do
  590.     {
  591.             // align destination
  592.         if ( alignA & 1)
  593.             *((char *)dst)++ = *((char *)src)++;
  594.         if ( alignA & 2)
  595.             *((short *)dst)++ = *((short *)src)++;
  596.     
  597.             // copy 32 byte blocks
  598.         for ( x = 0; x < leftblocks; x++)
  599.         {
  600.             *dstL++ = *srcL++;
  601.             *dstL++ = *srcL++;
  602.             *dstL++ = *srcL++;
  603.             *dstL++ = *srcL++;
  604.             *dstL++ = *srcL++;
  605.             *dstL++ = *srcL++;
  606.             *dstL++ = *srcL++;
  607.             *dstL++ = *srcL++;
  608.         }
  609.             // copy left-over bytes (<32)
  610.         for ( x = 0; x < leftwords; x++)
  611.             *((long *)dst)++ = *((long *)src)++;
  612.         if ( left & 2)
  613.             *((short *)dst)++ = *((short *)src)++;
  614.         if ( left & 1)
  615.             *((char *)dst)++ = *((char *)src)++;
  616.             
  617.         src += srcOffsetAtoB;
  618.         dst += dstOffsetAtoB;
  619.  
  620.             // align destination
  621.         if ( alignB & 1)
  622.             *((char *)dst)++ = *((char *)src)++;
  623.         if ( alignB & 2)
  624.             *((short *)dst)++ = *((short *)src)++;
  625.  
  626.             // copy 32 byte blocks
  627.         for ( x = 0; x < rightblocks; x++)
  628.         {
  629.             *dstL++ = *srcL++;
  630.             *dstL++ = *srcL++;
  631.             *dstL++ = *srcL++;
  632.             *dstL++ = *srcL++;
  633.             *dstL++ = *srcL++;
  634.             *dstL++ = *srcL++;
  635.             *dstL++ = *srcL++;
  636.             *dstL++ = *srcL++;
  637.         }
  638.  
  639.             // copy left-over bytes (<32)
  640.         for ( x = 0; x < rightwords; x++)
  641.             *((long *)dst)++ = *((long *)src)++;
  642.         if ( right & 2)
  643.             *((short *)dst)++ = *((short *)src)++;
  644.         if ( right & 1)
  645.             *((char *)dst)++ = *((char *)src)++;
  646.             
  647.         src += srcOffsetBtoA;
  648.         dst += dstOffsetBtoA;
  649.  
  650.     } while (--rows);
  651.  
  652. #endif // SW_PPC
  653.  
  654. }
  655. #undef    srcL
  656. #undef    dstL
  657. #undef    bufferL
  658. #undef    srcD
  659. #undef    dstD
  660. #undef    bufferD
  661.  
  662. #else // !USE_C == USE_ASM
  663.  
  664. #pragma mark *** 68k asm:
  665. #if !SW_PPC
  666.  
  667. //    This 680X0 asm implementation is
  668. //    ©1997 Anders Fredrik Björklund. All rights reserved.
  669. //    mailto:coderonin@geocities.com  ¡¡¡ FRONT LINE ASSEMBLER !!!
  670.  
  671. SW_ASM_FUNC void BlitDoubleRects(
  672.     char *src,
  673.     char *dst,
  674.     unsigned long rows,
  675.     unsigned long bytesA,
  676.     unsigned long bytesB,
  677.     OffsetInfoPtr info)
  678. {
  679. //    VARIABLE(S)        REGISTER
  680. //    *temp*            D0
  681. //    *temp*,y        D1
  682. //    bytesA,left        D2
  683. //    leftblocks        D3
  684. //    bytesB,right    D4
  685. //    dst                D5
  686. //    alignA            D6
  687. //    alignB            D7
  688. //    src                A0
  689. //    dst                A1
  690. //    startA            A2
  691. //    startB            A3
  692. //    offsetinfoptr    A4
  693.  
  694.     SW_ASM_BEGIN
  695.  
  696. #if __MWERKS__
  697.     fralloc
  698. #endif
  699.  
  700.     MOVEM.L      D3-D7/A2-A4,-(SP)
  701.     MOVEA.L      src,A0   
  702.      MOVEA.L      dst,A1
  703.     MOVE.L    bytesA,D2
  704.      MOVE.L    bytesB,D4
  705.  
  706.     // srcOffsetAtoB = info->srcOffsetAtoB;
  707.     // srcOffsetBtoA = info->srcOffsetBtoA;
  708.     // dstOffsetAtoB = info->dstOffsetAtoB;
  709.     // dstOffsetBtoA = info->dstOffsetBtoA;
  710.     MOVEA.L        info,A4
  711. #define srcOffsetAtoB        (A4)
  712. #define srcOffsetBtoA        4(A4)
  713. #define dstOffsetAtoB        8(A4)
  714. #define dstOffsetBtoA        12(A4)
  715.       
  716.         // alignment offset for rect A
  717.  //    align = (-((long) dst )) & 3
  718.     MOVE.L    A1,D6
  719.     MOVEQ     #3,D1
  720.     NEG.L     D6
  721.     AND.W     D1,D6
  722.  
  723.         // alignment offset for rect B
  724.  //    align = (-((long) dst + bytesA + dstOffsetAtoB)) & 3
  725.     MOVE.L    A1,D7
  726.     ADD.L     D2,D7
  727.     ADD.L     dstOffsetAtoB,D7
  728.     NEG.L     D7
  729.     AND.W     D1,D7
  730.  
  731. //    if ( alignA > bytesA)    alignA = bytesA;
  732.      CMP.W     D2,D6
  733.     BLE.S      @alignAok
  734.     MOVE.W    D2,D6
  735.  @alignAok:
  736. //  bytesB -= align;
  737.     SUB.W     D6,D2
  738.  
  739. //    if ( alignB > bytesB)    alignB = bytesB;
  740.      CMP.W     D4,D7
  741.     BLE.S      @alignBok
  742.     MOVE.W    D4,D7
  743.  @alignBok:
  744. //  bytesB -= align;
  745.     SUB.W     D7,D4
  746.       
  747.          //pre-calculate transfer sizes
  748.     MOVE.W    #15,D0
  749. //  leftblocks = bytesA >> 6;
  750. //    left = bytesA & 63;
  751.     MOVE.W    D2,D3
  752.     LSR.W     #6,D3
  753.  
  754. // calculate words outside blocks
  755.     MOVE.W    D2,D1
  756.     ANDI.W    #3,D2
  757.     LSR.W     #2,D1        // / sizeof(long)
  758.     AND.W     D0,D1
  759.      ADD.W      D1,D1        // * sizeof(MOVE.L (A0)+,(A1)+)
  760.     LEA          @leftloopend,A2
  761.     SUBA.L      D1,A2    
  762.     
  763. //  rightblocks = bytesB >> 6;
  764. //    right = bytesB & 63;
  765.     MOVE.W    D4,D5
  766.     LSR.W     #6,D5
  767.  
  768.  // calculate words outside blocks
  769.     MOVE.W    D4,D1
  770.     ANDI.W    #3,D4
  771.     LSR.W     #2,D1        // / sizeof(long)
  772.     AND.W      D0,D1
  773.     ADD.W      D1,D1        // * sizeof(MOVE.L (A0)+,(A1)+)
  774.     LEA          @rightloopend,A3
  775.     SUBA.L      D1,A3    
  776.  
  777. //    if (rows) do
  778. //    {
  779.     MOVE.L    rows,D1
  780.     TST.W     D1
  781.     BEQ       @end
  782. @rowloop:    
  783.  
  784.         MOVE.W    D6,D0
  785.           ANDI.W    #1,D0
  786.           BEQ.S    @skipalignAbyte
  787.           MOVE.B    (A0)+,(A1)+
  788.       @skipalignAbyte:
  789.           MOVE.W    D6,D0
  790.           ANDI.W    #2,D0
  791.           BEQ.S    @skipalignAword
  792.           MOVE.W    (A0)+,(A1)+
  793.       @skipalignAword:
  794.  
  795.     // copy 64 byte blocks
  796.            MOVE.W    D3,D0
  797.            JMP        (A2)
  798.    @leftloop:
  799.         MOVE.L    (A0)+,(A1)+
  800.         MOVE.L     (A0)+,(A1)+
  801.         MOVE.L    (A0)+,(A1)+
  802.         MOVE.L    (A0)+,(A1)+
  803.         
  804.         MOVE.L    (A0)+,(A1)+
  805.         MOVE.L    (A0)+,(A1)+
  806.         MOVE.L     (A0)+,(A1)+
  807.         MOVE.L    (A0)+,(A1)+
  808.         
  809.         MOVE.L    (A0)+,(A1)+
  810.         MOVE.L     (A0)+,(A1)+
  811.         MOVE.L    (A0)+,(A1)+
  812.         MOVE.L    (A0)+,(A1)+
  813.         
  814.         MOVE.L    (A0)+,(A1)+
  815.         MOVE.L    (A0)+,(A1)+
  816.         MOVE.L     (A0)+,(A1)+
  817.         MOVE.L    (A0)+,(A1)+
  818.     @leftloopend:
  819.            DBRA    D0,@leftloop
  820.    
  821.           MOVE.W    D2,D0
  822.           BEQ.S    @skipleftbyte
  823.           SUBQ.W    #2,D0
  824.           BMI.S    @leftbyte
  825.           MOVE.W    (A0)+,(A1)+
  826.           TST      D0
  827.           BEQ.S    @skipleftbyte
  828.       @leftbyte:
  829.          MOVE.B    (A0)+,(A1)+
  830.       @skipleftbyte:
  831.      
  832.     //    src += srcOffsetAtoB;
  833.     //    dst += dstOffsetAtoB;
  834.     ADDA.L    srcOffsetAtoB,A0
  835.     ADDA.L    dstOffsetAtoB,A1
  836.  
  837.     // align destination to 4-byte boundary
  838.           MOVE.W    D7,D0
  839.           ANDI.W    #1,D0
  840.           BEQ.S    @skipalignBbyte
  841.           MOVE.B    (A0)+,(A1)+
  842.       @skipalignBbyte:
  843.           MOVE.W    D7,D0
  844.           ANDI.W    #2,D0
  845.           BEQ.S    @skipalignBword
  846.           MOVE.W    (A0)+,(A1)+
  847.       @skipalignBword:
  848.          
  849.             // copy 64 byte blocks
  850.         MOVE.W    D5,D0
  851.            JMP        (A3)
  852.    @rightloop:
  853.         MOVE.L    (A0)+,(A1)+
  854.         MOVE.L     (A0)+,(A1)+
  855.         MOVE.L    (A0)+,(A1)+
  856.         MOVE.L     (A0)+,(A1)+
  857.         
  858.         MOVE.L    (A0)+,(A1)+
  859.         MOVE.L    (A0)+,(A1)+
  860.         MOVE.L    (A0)+,(A1)+
  861.         MOVE.L     (A0)+,(A1)+
  862.         
  863.         MOVE.L    (A0)+,(A1)+
  864.         MOVE.L    (A0)+,(A1)+
  865.         MOVE.L     (A0)+,(A1)+
  866.         MOVE.L    (A0)+,(A1)+
  867.         
  868.         MOVE.L    (A0)+,(A1)+
  869.         MOVE.L    (A0)+,(A1)+
  870.         MOVE.L     (A0)+,(A1)+
  871.         MOVE.L    (A0)+,(A1)+
  872.     @rightloopend:
  873.            DBRA    D0,@rightloop
  874.     
  875.          MOVE.W    D4,D0
  876.           BEQ.S    @skiprightbyte
  877.           SUBQ.W    #2,D0
  878.           BMI.S    @rightbyte
  879.           MOVE.W    (A0)+,(A1)+
  880.           TST      D0
  881.           BEQ.S    @skiprightbyte
  882.       @rightbyte:
  883.          MOVE.B    (A0)+,(A1)+
  884.       @skiprightbyte:
  885.  
  886.      //    src += srcOffsetBtoA;
  887.        //  dst += dstOffsetBtoA;
  888.     ADDA.L    srcOffsetBtoA,A0
  889.     ADDA.L    dstOffsetBtoA,A1
  890.  
  891. //    } while (--rows);
  892.     SUBQ.W    #1,D1
  893.     BNE       @rowloop
  894.  
  895.  @end:
  896. #undef srcOffsetAtoB
  897. #undef srcOffsetBtoA
  898. #undef dstOffsetAtoB
  899. #undef dstOffsetBtoA
  900.     MOVEM.L      (SP)+,D3-D7/A2-A4
  901.  
  902. #if __MWERKS__
  903.     frfree
  904. #endif
  905.     
  906.     SW_ASM_END
  907. }
  908.  
  909. #endif    //#if !SW_PPC
  910.  
  911. #pragma mark *** PowerPC asm:
  912. #if SW_PPC
  913.  
  914. //    This PowerPC asm implementation is
  915. //    ©1997-98 Anders Fredrik Björklund. All rights reserved.
  916. //    mailto:coderonin@geocities.com        ¡¡¡ RISC RULEZ !!!
  917.  
  918. asm void BlitDoubleRects(
  919.     register char *src,
  920.     register char *dst,
  921.     register unsigned long rows,
  922.     register unsigned long bytesA,
  923.     register unsigned long bytesB,
  924.     register OffsetInfoPtr info)
  925. {
  926. // LOCAL VARIABLES:
  927. #define y                    r31
  928. #define alignA                r30
  929. #define alignB                r29
  930. #define leftdoubles            r30        // recycled
  931. #define rightdoubles        r29        // recycled
  932.  
  933. #define srcOffsetAtoB        r28
  934. #define srcOffsetBtoA        r27
  935. #define dstOffsetAtoB        r26
  936. #define dstOffsetBtoA        r25
  937.  
  938. #define leftblocks            r24
  939. #define left                r23
  940. #define rightblocks            r22
  941. #define right                r21
  942.  
  943. #define buffer                r20
  944. #define offset                r19
  945.  
  946. #define    kRegisterSaveStack    (13 * 4)
  947.  
  948.     stmw     r19,-kRegisterSaveStack(SP)    // save registers on stack (in the "red zone")
  949.  
  950. // PARAMETERS:
  951. //    src            r3
  952. //    dst            r4
  953. #define rows    r5
  954. #define bytesA    r6
  955. #define bytesB    r7
  956. #define info    r8
  957.  
  958. //    srcOffsetAtoB = info->srcOffsetAtoB;
  959. //    srcOffsetBtoA = info->srcOffsetBtoA;
  960. //    dstOffsetAtoB = info->dstOffsetAtoB;
  961. //    dstOffsetBtoA = info->dstOffsetBtoA;
  962.     lwz     srcOffsetAtoB,0(info)
  963.     lwz     srcOffsetBtoA,4(info)
  964.     lwz     dstOffsetAtoB,8(info)
  965.     lwz     dstOffsetBtoA,12(info)
  966.  
  967.         // get a cache-block aligned stack storage for buffer
  968.     addi        buffer,SP,-(kRegisterSaveStack + 32)    // (still in the red zone)
  969.     rlwinm        buffer,buffer,0,0,26    
  970.     dcbtst        r0,buffer
  971.     
  972.         // alignment offset for rect A
  973. //    align = (-((long) dst )) & 7
  974.     neg        alignA,r4
  975.     rlwinm    alignA,alignA,0,29,31
  976.         
  977. //    if ( alignA > bytesA)    alignA = bytesA;
  978. //    bytesA -= alignA;
  979.     cmplw    alignA,bytesA
  980.     ble        @alignAok
  981.     mr        alignA,bytesA
  982. @alignAok:
  983.     sub        bytesA,bytesA,alignA
  984.  
  985.     neg        r9,r3
  986.     rlwinm    r9,r9,0,30,31
  987.  
  988.         // alignment offset for rect B
  989. //    align = (-((long) dst + bytesA + dstOffsetAtoB)) & 7
  990.     add        r0,bytesA,dstOffsetAtoB
  991.     add        alignB,r4,r0
  992.     neg        alignB,alignB
  993.     rlwinm    alignB,alignB,0,29,31
  994.         
  995. //    if ( alignB > bytesB)    alignB = bytesB;
  996. //    bytesB -= alignB
  997.     cmplw    alignB,bytesB
  998.     ble        @alignBok
  999.     mr        alignB,bytesB
  1000. @alignBok:
  1001.     sub        bytesB,bytesB,alignB
  1002.  
  1003.     add        r0,bytesA,srcOffsetAtoB
  1004.     add        r10,r3,r0
  1005.     neg        r10,r10
  1006.     rlwinm    r10,r10,0,30,31
  1007.  
  1008. // ———————————————————————————————————————————————————————————————————————————
  1009.  
  1010.         //pre-calculate transfer sizes
  1011.     rlwinm   leftblocks,bytesA,27,5,31        //    leftblocks = bytesA / 32;
  1012.     rlwinm   left,bytesA,0,27,31            //    left = bytesA % 32;
  1013.     rlwinm   rightblocks,bytesB,27,5,31        //    rightblocks = bytesB / 32;
  1014.     rlwinm   right,bytesB,0,27,31            //    right = bytesB % 32;
  1015.  
  1016.     mr.        y,rows
  1017.     ble        @gohome
  1018.  
  1019.     mfcr    r0            // save CR in r0
  1020. //    NOTE : don't use r0 from here and below (except as zero)
  1021.     
  1022.     rlwinm  alignA,alignA,5*4,9,11
  1023.     mtcrf    32,alignA            // cr2 = alignA & 7
  1024.     
  1025.     rlwinm  alignB,alignB,2*4,21,23
  1026.     mtcrf    4,alignB            // cr5 = alignB & 7
  1027.  
  1028.     rlwinm  alignA,alignA,12,29,31    // shift back, and with 3
  1029.     rlwinm  alignB,alignB,24,29,31
  1030.     cmplw    cr0,alignA,r9
  1031.     cmplw    cr1,alignB,r10
  1032.  
  1033.     cmplwi    cr3,leftblocks,0
  1034.     cmplwi    cr4,left,0
  1035.     cmplwi    cr6,rightblocks,0
  1036.     cmplwi    cr7,right,0
  1037.  
  1038.     bne        cr0,@leftNotAligned
  1039.     rlwinm. leftdoubles,left,29,30,31
  1040.     rlwinm  left,left,3*4,17,19
  1041.     creqv    12,12,12            // crset    cr3_LT
  1042.     mtcrf    8,left                // cr4 = left & 7
  1043.     crnor    16,2,2                // cr4_LT = leftdoubles > 0
  1044. @leftNotAligned:
  1045.  
  1046.     bne        cr1,@rightNotAligned
  1047.     rlwinm. rightdoubles,right,29,30,31
  1048.     rlwinm  right,right,0*4,29,31
  1049.     creqv    24,24,24            // crset    cr6_LT
  1050.     mtcrf    1,right                // cr7 = right & 7
  1051.     crnor    28,2,2                // cr7_LT = rightdoubles > 0
  1052. @rightNotAligned:
  1053.  
  1054.     li        offset,32
  1055.     sub        r3,r3,offset
  1056.     sub        r4,r4,offset
  1057.  
  1058. @rowloop:
  1059. // ———————————————————————————————————————————————————————————————————————————
  1060. //  NOTE: from here on, regs r5-r12 are scratch!
  1061. //    NOTE : cr0 is used for rows (y), cr1 is free
  1062.  
  1063.             //    align destination
  1064.         bns        cr2,@skipalignAByte
  1065.         lbz        r5,32(r3)
  1066.         addi    r3,r3,1
  1067.         stb        r5,32(r4)
  1068.         addi    r4,r4,1
  1069.     @skipalignAByte:
  1070.         bne        cr2,@skipalignAWord
  1071.         lhz        r5,32(r3)
  1072.         addi    r3,r3,2
  1073.         sth        r5,32(r4)
  1074.         addi    r4,r4,2
  1075.     @skipalignAWord:
  1076.         bng        cr2,@skipalignALong
  1077.         lwz        r5,32(r3)
  1078.         addi    r3,r3,4
  1079.         stw        r5,32(r4)
  1080.         addi    r4,r4,4
  1081.     @skipalignALong:
  1082.     
  1083.             // copy 32 byte blocks
  1084.         blt         cr3,@leftAligned
  1085.         beq         cr3,@skipleft
  1086.         mtctr     leftblocks
  1087.     @leftloop:    
  1088.         lwzu     r5,32(r3)
  1089.         lwz      r6,4(r3)
  1090.         lwz      r7,8(r3)
  1091.         lwz      r8,12(r3)
  1092.         stw      r5,0(buffer)
  1093.         stw      r6,4(buffer)
  1094.         stw      r7,8(buffer)
  1095.         stw      r8,12(buffer)
  1096.         lwz      r9,16(r3)
  1097.         lwz      r10,20(r3)
  1098.         lwz      r11,24(r3)
  1099.         lwz      r12,28(r3)
  1100.         lfd      fp1,0(buffer)
  1101.         lfd      fp2,8(buffer)
  1102.         stw      r9,16(buffer)
  1103.         stw      r10,20(buffer)
  1104.         stw      r11,24(buffer)
  1105.         stw      r12,28(buffer)
  1106.         lfd      fp3,16(buffer)
  1107.         lfd      fp4,24(buffer)
  1108.         stfdu    fp1,32(r4)
  1109.         stfd     fp2,8(r4)
  1110.         stfd     fp3,16(r4)
  1111.         stfd     fp4,24(r4)
  1112.         bdnz     @leftloop
  1113.     @skipleft:
  1114.     
  1115.     // copy left-over bytes (<32)
  1116.         beq        cr4,@endleft
  1117.         mtxer    left
  1118.         lswx    r5,offset,r3
  1119.         add        r3,r3,left
  1120.         stswx    r5,offset,r4
  1121.         add        r4,r4,left
  1122.         b        @endleft
  1123.  
  1124.     @leftAligned:
  1125.         beq         cr3,@skipleftAligned
  1126.         mtctr     leftblocks
  1127.     @leftloopAligned:
  1128.         lfdu     fp1,32(r3)
  1129.         lfd      fp2,8(r3)
  1130.         lfd      fp3,16(r3)
  1131.         lfd      fp4,24(r3)
  1132.         stfdu    fp1,32(r4)
  1133.         stfd     fp2,8(r4)
  1134.         stfd     fp3,16(r4)
  1135.         stfd     fp4,24(r4)
  1136.         bdnz     @leftloopAligned
  1137.     @skipleftAligned:
  1138.  
  1139.         bnl         cr4,@skipADoubles
  1140.         mtctr     leftdoubles
  1141.     @leftloopDouble:
  1142.         lfd      fp0,32(r3)
  1143.         addi     r3,r3,8
  1144.         stfd     fp0,32(r4)
  1145.         addi     r4,r4,8
  1146.         bdnz     @leftloopDouble
  1147.     @skipADoubles:
  1148.         bng         cr4,@skipALong
  1149.         lwz         r5,32(r3)
  1150.         addi     r3,r3,4
  1151.         stw         r5,32(r4)
  1152.         addi     r4,r4,4
  1153.     @skipALong:
  1154.         bne         cr4,@skipAWord
  1155.         lhz         r5,32(r3)
  1156.         addi     r3,r3,2
  1157.         sth         r5,32(r4)
  1158.         addi     r4,r4,2
  1159.     @skipAWord:
  1160.         bns         cr4,@skipAByte
  1161.         lbz         r5,32(r3)
  1162.         addi     r3,r3,1
  1163.         stb       r5,32(r4)
  1164.         addi     r4,r4,1
  1165.     @skipAByte:
  1166.     
  1167.     @endleft:
  1168.         add     r3,r3,srcOffsetAtoB
  1169.         add     r4,r4,dstOffsetAtoB
  1170.  
  1171. // ———————————————————————————————————————————————————————————————————————————
  1172.  
  1173.         //    align destination
  1174.         bns        cr5,@skipalignBByte
  1175.         lbz        r5,32(r3)
  1176.         addi    r3,r3,1
  1177.         stb        r5,32(r4)
  1178.         addi    r4,r4,1
  1179.     @skipalignBByte:
  1180.         bne        cr5,@skipalignBWord
  1181.         lhz        r5,32(r3)
  1182.         addi    r3,r3,2
  1183.         sth        r5,32(r4)
  1184.         addi    r4,r4,2
  1185.     @skipalignBWord:
  1186.         bng        cr5,@skipalignBLong
  1187.         lwz        r5,32(r3)
  1188.         addi    r3,r3,4
  1189.         stw        r5,32(r4)
  1190.         addi    r4,r4,4
  1191.     @skipalignBLong:
  1192.     
  1193.             // copy 32 byte blocks
  1194.         blt         cr6,@rightAligned
  1195.         beq         cr6,@skipright
  1196.         mtctr     rightblocks
  1197.     @rightloop:    
  1198.         lwzu     r5,32(r3)
  1199.         lwz      r6,4(r3)
  1200.         lwz      r7,8(r3)
  1201.         lwz      r8,12(r3)
  1202.         stw      r5,0(buffer)
  1203.         stw      r6,4(buffer)
  1204.         stw      r7,8(buffer)
  1205.         stw      r8,12(buffer)
  1206.         lwz      r9,16(r3)
  1207.         lwz      r10,20(r3)
  1208.         lwz      r11,24(r3)
  1209.         lwz      r12,28(r3)
  1210.         lfd      fp1,0(buffer)
  1211.         lfd      fp2,8(buffer)
  1212.         stw      r9,16(buffer)
  1213.         stw      r10,20(buffer)
  1214.         stw      r11,24(buffer)
  1215.         stw      r12,28(buffer)
  1216.         lfd      fp3,16(buffer)
  1217.         lfd      fp4,24(buffer)
  1218.         stfdu    fp1,32(r4)
  1219.         stfd     fp2,8(r4)
  1220.         stfd     fp3,16(r4)
  1221.         stfd     fp4,24(r4)
  1222.         bdnz     @rightloop
  1223.     @skipright:
  1224.     
  1225.     // copy left-over bytes (<32)
  1226.         beq        cr7,@endright
  1227.         mtxer    right
  1228.         lswx    r5,offset,r3
  1229.         add        r3,r3,right
  1230.         stswx    r5,offset,r4
  1231.         add        r4,r4,right
  1232.         b        @endright
  1233.  
  1234.     @rightAligned:
  1235.         beq         cr6,@skiprightAligned
  1236.         mtctr     rightblocks
  1237.     @rightloopAligned:
  1238.         lfdu     fp1,32(r3)
  1239.         lfd      fp2,8(r3)
  1240.         lfd      fp3,16(r3)
  1241.         lfd      fp4,24(r3)
  1242.         stfdu    fp1,32(r4)
  1243.         stfd     fp2,8(r4)
  1244.         stfd     fp3,16(r4)
  1245.         stfd     fp4,24(r4)
  1246.         bdnz     @rightloopAligned
  1247.     @skiprightAligned:
  1248.  
  1249.         bnl         cr7,@skipBDoubles
  1250.         mtctr     rightdoubles
  1251.     @rightloopDouble:
  1252.         lfd      fp0,32(r3)
  1253.         addi     r3,r3,8
  1254.         stfd     fp0,32(r4)
  1255.         addi     r4,r4,8
  1256.         bdnz     @rightloopDouble
  1257.     @skipBDoubles:
  1258.         bng         cr7,@skipBLong
  1259.         lwz         r5,32(r3)
  1260.         addi     r3,r3,4
  1261.         stw         r5,32(r4)
  1262.         addi     r4,r4,4
  1263.     @skipBLong:
  1264.         bne         cr7,@skipBWord
  1265.         lhz         r5,32(r3)
  1266.         addi     r3,r3,2
  1267.         sth         r5,32(r4)
  1268.         addi     r4,r4,2
  1269.     @skipBWord:
  1270.         bns         cr7,@skipBByte
  1271.         lbz         r5,32(r3)
  1272.         addi     r3,r3,1
  1273.         stb       r5,32(r4)
  1274.         addi     r4,r4,1
  1275.     @skipBByte:
  1276.     
  1277.     @endright:
  1278.     
  1279. // ———————————————————————————————————————————————————————————————————————————
  1280.  
  1281.         subic.   y,y,1
  1282.  
  1283.         add      r3,r3,srcOffsetBtoA
  1284.         add      r4,r4,dstOffsetBtoA
  1285.         
  1286.     bne @rowloop
  1287.  
  1288. @end:
  1289.     mtcrf    0xFF,r0            // restore CR    (mtcr r0)
  1290. @gohome:
  1291. #undef y
  1292. #undef leftblocks
  1293. #undef left    
  1294. #undef rightblocks    
  1295. #undef right    
  1296. #undef alignA
  1297. #undef alignB    
  1298. #undef srcOffsetAtoB
  1299. #undef srcOffsetBtoA
  1300. #undef dstOffsetAtoB
  1301. #undef dstOffsetBtoA    
  1302. #undef buffer    
  1303. #undef offset    
  1304.     lmw     r19,-kRegisterSaveStack(SP)        // restore registers from stack
  1305. #undef rows
  1306. #undef bytesA
  1307. #undef bytesB
  1308. #undef info
  1309.     blr
  1310. }
  1311. #endif //#if SW_PPC
  1312.  
  1313. #endif //#if THEORY/USE_C/USE_ASM